package com.ruoyi.framework.propertySourcesEnc;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySources;
import org.springframework.core.env.PropertySourcesPropertyResolver;

import java.util.Map;
import java.util.Objects;

/**
 * A custom implementation of {@link PropertySourcesPropertyResolver} which can resolve encrypted properties as well.
 */
@Setter
@Getter
public class EncryptionAwarePropertySourcesPropertyResolver extends PropertySourcesPropertyResolver {

    private EncryptionAwareService encryptionAwareService;

    public EncryptionAwarePropertySourcesPropertyResolver(Environment environment) {
        super(((ConfigurableEnvironment) environment).getPropertySources());
    }

    public EncryptionAwarePropertySourcesPropertyResolver(PropertySources propertySources, EncryptionAwareService encryptionAwareService) {
        super(propertySources);
        this.encryptionAwareService = encryptionAwareService;
    }

    @Setter
    @Getter
    public static class InnerPropertySource extends MapPropertySource {

        private EncryptionAwareService encryptionAwareService;

        /**
         * Create a new {@code MapPropertySource} with the given name and {@code Map}.
         *
         * @param name   the associated name
         * @param source the Map source (without {@code null} values in order to get
         *               consistent {@link #getProperty} and {@link #containsProperty} behavior)
         */
        public InnerPropertySource(String name, Map<String, Object> source) {
            super(name, source);
        }

        public InnerPropertySource(String name, Map<String, Object> source, EncryptionAwareService encryptionAwareService) {
            super(name, source);
            this.encryptionAwareService = encryptionAwareService;
        }

        // 每次 environment.getProperty(name) 的时候,都会检测 PropertySources.getProperty(name)
        @Override
        public Object getProperty(String name) {
            Object value = super.getProperty(name);
            if (Objects.isNull(encryptionAwareService)) return value;
            if (value instanceof String) {
                return encryptionAwareService.tryDecrypt(String.valueOf(value));
            }
            if (value instanceof OriginTrackedValue) {
                Object originValue = ((OriginTrackedValue) value).getValue();
                // 避免循环依赖
//              return encryptionAwareService.tryDecrypt(String.valueOf(originValue));
                return originValue;
            }
            return value;
        }
    }

}